<?php
// Copyright 2011 Zeptonic Ek. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
//    conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
//    of conditions and the following disclaimer in the documentation and/or other materials
//    provided with the distribution.
// 
// THIS SOFTWARE IS PROVIDED BY Zeptonic Ek ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Zeptonic Ek OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// 
// The views and conclusions contained in the software and documentation are those of the 
// authors and should not be interpreted as representing official policies, 
// either expressed or implied, of Zeptonic Ek.


/**
 * Url-hantering.
 * 
 * @category Golfscraper
 * @package  Golfscraper
 * @author   Anders Axelsson <anders@zeptonic.com>
 * @author   Mattias Tiger <mattias@zeptonic.com>
 * @link     http://www.zeptonic.com
 */
class Url_handler {
	/**
	 * Hämtar bas-url från en url.
	 * Tex http://domain.com/foo/bar/site.x blir http://domain.com.
	 *
	 * @param String $url Url att hämta bas-url från
	 *
	 * @return String
	 */
	public static function base_url($url) {
		$protocol = substr($url, 0, strpos($url, "://") + 3);
		$url = substr($url, strpos($url, "://") + 3, strlen($url));
		$pos = strpos($url, "/");
		if($pos)
			$url = substr($url, 0, $pos);
		$url = $protocol . $url;
		return $url;
	}
	
	/**
	 * Returnerar filnamnet på scriptet i en url.
	 * Om inget filnamn finns då returneras falskt.
	 *
	 * @param String $url Url att hämta filnamn ur
	 *
	 * @return Mixed
	 */
	public static function filename($url) {
		$path = parse_url($url, PHP_URL_PATH);
		$path_parts = explode("/", $path);
		$count_parts = count($path_parts);
		$last_idx = 0;
		if($count_parts > 0) {
			$last_idx = $count_parts - 1;
		}
		$last_part = $path_parts[$last_idx];
		if(!String::in_string($last_part, ".")) {
			return false;
		} else {
			return trim($last_part, "/");
		}
	}
	
	/**
	 * Returnerar sökvägen till filen i en url.
	 * Tex http://domain.com/dir/to/path/file.x http://domain.com/blir dir/to/path/
	 * Om ingen sökväg finns returneras falskt.
	 *
	 * @param String $url Url att hämta sökväg ur
	 *
	 * @return Mixed
	 */
	public static function dir_path($url) {
		// något konstig funktion, borde skrivas om
		$protocol = substr($url, 0, strpos($url, "://") + 3);
		$url = substr($url, strpos($url, "://") + 3, strlen($url));
		
		preg_match('/([a-z|A-Z|0-9|\.|\?|\&|\=|\-|\_|\/]*\/)/', $url, $out);
		
		if(count($out) == 0 || count($out[0]) == 0)
			return false;
		
		$out = $protocol . $out[0];
		return $out;
	}
	
	/**
	 * Returnerar querystring i en url.
	 * Om ingen querystring finns då returneras falskt.
	 *
	 * @param String $url Url att hämta querystring ur
	 *
	 * @return Mixed
	 */
	public static function query($url) {
		$query = parse_url($url, PHP_URL_QUERY);
		if(empty($query))
			return false;
		return $query;
	}
	
	/**
	 * Returnerar filnamnet på scriptet samt eventuell querystring i en url.
	 * Om inget filnamn finns då returneras bara querystring:en.
	 *
	 * @param String $url Url att hämta filnamn och querystring ur
	 *
	 * @return String
	 */
	public static function script_and_query($url) {
		$path = parse_url($url, PHP_URL_PATH);
		$query = parse_url($url, PHP_URL_QUERY);
		$path_parts = explode("/", $path);
		$count_parts = count($path_parts);
		$last_idx = 0;
		if($count_parts > 0) {
			$last_idx = $count_parts - 1;
		}
		$last_part = $path_parts[$last_idx];
		
		if(!String::in_string($last_part, ".")) {
			return "?" . $query;
		} else {
			$script_and_query = trim($last_part, "/");
			if(!empty($query)) {
				$script_and_query .= "?" . $query;
			}
			return $script_and_query;
		}
	}
	
	/**
	 * Gör en absolut url av en relativ.
	 *
	 * @param String $relativ_url Relativ url 
	 * @param String $base_url Bas-url, tex http://domain.com
	 *
	 * @return String
	 */
	public static function absolute_url($relative_url, $base_url) {
		if(Url_handler::is_absolute_url($relative_url))
			return $relative_url;
		return trim($base_url, "/") . "/" . trim($relative_url, "/");
	}
	
	/**
	 * Kontrollerar om en url är absolut eller inte.
	 *
	 * @param String $url Url att testa
	 *
	 * @return Boolean
	 */
	public static function is_absolute_url($url) {
		preg_match('/\/([a-z|A-Z|0-9|\/|\.|\?|\&|\=|\-|\_]*)/', $url, $out);
		
		if(count($out) == 0 || count($out[0]) == 0)
			return false;
			
		// om den är absolut är $out[0] == //path
		// annars $out[0] == /path
		$result = substr($out[0], 0, 1) == "/";
		$result &= strlen($out[0]) > 1;
		$result &= substr($out[0], 1, 1) == "/";
		return $result;
	}
	
	/**
	 * Ersätter relativa med absoluta url:er med hjälp av regex.
	 * 
	 * @param String $pattern Regex mönster för att finna relativa url:er.
	 * @param String $content Innehåll att ersättar url:er i
	 * @param String $content_url Url till innehållet
	 * @param String $base_url Bas-url, tex http://domain.com
	 *
	 * @return String
	 */
	public static function relative_to_abs_urls($pattern, $content, $content_url, $base_url) {
		preg_match_all($pattern, $content, $out, PREG_PATTERN_ORDER);
		$content = preg_split($pattern, $content);
		foreach($out[1] as $key => $match) {
			$path_content = Url_handler::dir_path($content_url);
			$path_match = Url_handler::dir_path($match);
			$path = "";
			$file = "";
			if($path_match === false) {
				// bara filnamn i matchningen tex bild.jpg
				$path = $path_content;
				$file = trim($match, "/");
			} else {
				// det finns en sökväg i matchningen tex /path/to/bild.jpg
				
				// om sökvägen börjar med ett / då utgår man från sidans root-mapp
				// annars från css-filens mapp
				if(String::starts_with($path_match, "/")) {
					$path = trim($base_url, "/") . $path_match;
					$file = Url_handler::script_and_query($match);
				} else {
					$path = trim($path_content, "/");
					$file = $match;
				}
			}
			$path = trim($path, "/");
			
			$total_match = $out[0][$key];
			$total_match_len = strlen($total_match);
			$match_len = strlen($match);
			$match_start_pos = strpos($total_match, $match);
			$match_end_pos = $match_start_pos + $match_len;
			
			// tar ut det som omsluter matchningen
			$left_of_match = substr($total_match, 0, $match_start_pos);
			$right_of_match = substr($total_match, $match_end_pos, $total_match_len - $match_end_pos);
			
			// ersätter matchningen med en absolut sökväg 
			$adjusted_total_match = $left_of_match . $path . "/" . $file . $right_of_match;
			
			$content[$key] = $content[$key] . $adjusted_total_match;
		}
		$content = implode("", $content);
		return $content;
	}
	
	/**
	 * Ersätter relativa url:er mellan citattecken (' eller ")  med absoluta url:er.
	 * 
	 * @param String $content Innehåll att ersättar url:er i
	 * @param String $content_url Url till innehållet
	 * @param String $base_url Bas-url, tex http://domain.com
	 *
	 * @return String
	 */
	public static function quoted_relative_to_abs_urls($content, $content_url, $base_url) {
		$pattern = '/[\']((\/[a-z|A-Z|0-9|\.|\?|\=|\&|\-|\_]+)+[^\/])[\']/';
		$content = Url_handler::relative_to_abs_urls($pattern, $content, $content_url, $base_url);
		
		$pattern = '/[\"]((\/[a-z|A-Z|0-9|\.|\?|\=|\&|\-|\_]+)+[^\/])[\"]/';
		$content = Url_handler::relative_to_abs_urls($pattern, $content, $content_url, $base_url);
		
		return $content;
	}
	
	/**
	 * Ersätter alla relativa url:er som innehåller backning genom filsystemet
	 * dvs innehåller godtyckligt många "../".
	 *
	 * @param String $content Innehåll att ersättar url:er i
	 * @param String $content_url Url till innehållet
	 * @param String $base_url Bas-url, tex http://domain.com
	 *
	 * @return String
	 */
	public static function backing_relative_to_abs_urls($content, $content_url, $base_url) {
		preg_match_all("/(\.\.\/)+/", $content, $out, PREG_PATTERN_ORDER);
		$content = preg_split("/(\.\.\/)+/", $content);
		
		$path = trim(parse_url($content_url, PHP_URL_PATH), "/");
		$query = parse_url($content_url, PHP_URL_QUERY);
		$path = trim($path . "?" . $query, "?");
		
		foreach($out[0] as $key => $match) {
			$count = substr_count($match, "../");
			$reg = "";
			
			if($count > 0) {
				//alla oönskade mappar (backar igenom dem)
				for($i = 0; $i < $count; $i++) {
					$reg .= "([a-z|A-Z|0-9|\-|\_]*\/)";
				}
				// lägger till godtyckligt antal mappar före den oönskade
				$reg = "(([a-z|A-Z|0-9|\-|\_]*\/)*)" . $reg;
				preg_match("/" . $reg . "/", $path, $glue);
				if(count($glue)) {
					$glue = $glue[1]; //första parantesen väljs
					$content[$key] = $content[$key] . $base_url . "/" . $glue;
				}
			}
		}
		$content = implode("", $content);
		return $content;
	}

	/**
	 * Hämtar den aktuella URL:en.
	 * 
	 * @return String
	 */
	public static function current_url() {
		if(!isset($_SERVER['REQUEST_URI'])) {
			$serverrequri = $_SERVER['PHP_SELF'];
		} else {
			$serverrequri = $_SERVER['REQUEST_URI'];
		}
		$s = empty($_SERVER["HTTPS"]) ? '' : ($_SERVER["HTTPS"] == "on") ? "s" : "";
		$protocol = String::left(strtolower($_SERVER["SERVER_PROTOCOL"]), "/") . $s;
				
		$port = ($_SERVER["SERVER_PORT"] == "80") ? "" : (":" . $_SERVER["SERVER_PORT"]);
		return $protocol . "://" . $_SERVER['SERVER_NAME'] . $port . $serverrequri;
	}
}
?>
